﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sustainalytics.LongRunningTaskManager;
using Sustainalytics.LongRunningTaskManager.Interface;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

namespace Sustainalytics.DataLayer.Tests
{
    [TestClass]
    public class LongRunningTaskInstanceSnapshotRepositoryTests
    {
        ILongRunningTaskResultFactory _taskResFactory;
        ILongRunningTaskInstanceSnapshotRepository _repo;
        List<LongRunningTaskInstanceSnapshot> _data;

        [TestInitialize]
        public void TestInitialize()
        {
            string connStr = ConfigurationManager.ConnectionStrings["ClientPlatform_Test"].ConnectionString;
            _taskResFactory = new LongRunningTaskResultFactory();
            _repo = new LongRunningTaskInstanceSnapshotRepository(connStr, _taskResFactory);

            _repo.Clear();

            PopulateDb();
        }

        [TestCleanup]
        public void TestCleanup()
        {
            _repo.Clear();
        }

        private void PopulateDb()
        {
            #region DATA
            _data = new List<LongRunningTaskInstanceSnapshot>
            {
                new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 1 }",
                    Result = new LongRunningTaskObjectResult{ Data = 123},
                    ResultType = LongRunningTaskResultTypeEnum.Object,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details1",
                            Progress = 10.3f
                        }
                    },
                    Title = "Title 1",
                    Type = LongRunningTaskTypeEnum.PiReportPdf,
                    Username = "user1",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                },

                new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 2 }",
                    Result = new LongRunningTaskFileInMemResult 
                    { 
                        Contents = new byte[] { 1, 2, 3 }, 
                        EnforceInMemory = true, 
                        MimeType = "application/octet-stream", 
                        FileName = "f2"
                    },
                    ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details2",
                            Progress = 50.5f
                        }
                    },
                    Title = "Title 2",
                    Type = LongRunningTaskTypeEnum.GccsReportPdf,
                    Username = "user2",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                },

                new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 3 }",
                    Result = new LongRunningTaskFileOnDiskResult 
                    { 
                        ContentLength = 3,
                        FilePath = @"C:\Folder\file.txt",
                        MimeType = "application/octet-stream", 
                        FileName = "f3"
                    },
                    ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Failed,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details3",
                            Progress = 70.0f
                        }
                    },
                    Title = "Title 3",
                    Type = LongRunningTaskTypeEnum.GccsReportPdf,
                    Username = "user3",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                },
            };
            #endregion


            // insert test data
            _repo.Insert(_data);
        }


        [TestMethod]
        public void Get_Success()
        {
            var expectedValue = _data.FirstOrDefault();

            var value = _repo.Get(expectedValue.Id);

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(new LongRunningTaskInstanceSnapshot().Equals(expectedValue, value));
        }

        [TestMethod]
        public void GetAll_Success()
        {
            var expectedValue = _data.OrderBy(el => el.Order).ToList();

            var value = _repo.GetAll();

            Assert.IsNotNull(value, "Returned value is null");
            Assert.IsTrue(expectedValue.SequenceEqual(value, new LongRunningTaskInstanceSnapshot()));
        }

        [TestMethod]
        public void Insert_Snapshot_Success()
        {
            var expectedValue = new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 4 }",
                    Result = new LongRunningTaskFileInMemResult
                    {
                        Contents = new byte[] { 1, 2, 3 },
                        EnforceInMemory = true,
                        MimeType = "application/octet-stream",
                        FileName = "f4"
                    },
                    ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details4",
                            Progress = 99f
                        }
                    },
                    Title = "Title 4",
                    Type = LongRunningTaskTypeEnum.GccsReportPdf,
                    Username = "user4",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                };

            _repo.Insert(expectedValue);

            var value = _repo.Get(expectedValue.Id);

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(new LongRunningTaskInstanceSnapshot().Equals(expectedValue, value), "Returned value is different than the expected value.");
        }

        [TestMethod]
        [ExpectedException(typeof(LongRunningTaskInstanceSnapshotNullException))]
        public void Insert_Snapshot_ArgumentNull_Error()
        {
            _repo.Insert((LongRunningTaskInstanceSnapshot)null);
        }

        [TestMethod]
        public void Insert_Snapshots_Success()
        {
            var expectedValues = new List<LongRunningTaskInstanceSnapshot>
            {
                new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 4 }",
                    Result = new LongRunningTaskFileInMemResult
                    {
                        Contents = new byte[] { 1, 2, 3 },
                        EnforceInMemory = true,
                        MimeType = "application/octet-stream",
                        FileName = "f4"
                    },
                    ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details4",
                            Progress = 99f
                        }
                    },
                    Title = "Title 4",
                    Type = LongRunningTaskTypeEnum.GccsReportPdf,
                    Username = "user4",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                },

                new LongRunningTaskInstanceSnapshot
                {
                    Id = Guid.NewGuid().ToString(),
                    ParamJson = "{ data: 5 }",
                    Result = new LongRunningTaskFileOnDiskResult 
                    { 
                        ContentLength = 3,
                        FilePath = @"C:\Folder\file.txt",
                        MimeType = "application/octet-stream", 
                        FileName = "f5"
                    },
                    ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                    Status = new LongRunningTaskInstanceStatus
                    {
                        TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Failed,
                        TaskStatus = new LongRunningTaskStatus
                        {
                            Details = "details5",
                            Progress = 99f
                        }
                    },
                    Title = "Title 5",
                    Type = LongRunningTaskTypeEnum.GccsReportPdf,
                    Username = "user5",
                    SnapshotDateCreated = DateTime.UtcNow,
                    Order = DateTime.UtcNow.Ticks
                }
            };

            _repo.Insert(expectedValues);

            var value = _repo.GetAll();

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(expectedValues.All(ev => value.Any(v => new LongRunningTaskInstanceSnapshot().Equals(ev, v))), "Returned value is different than the expected value.");
        }

        [TestMethod]
        [ExpectedException(typeof(LongRunningTaskInstanceSnapshotNullException))]
        public void Insert_Snapshots_ArgumentNull_Error()
        {
            _repo.Insert((IEnumerable<LongRunningTaskInstanceSnapshot>)null);
        }

        [TestMethod]
        [ExpectedException(typeof(LongRunningTaskInstanceSnapshotNullException))]
        public void Update_Snapshot_ArgumentNull_Error()
        {
            _repo.Update(null);
        }

        [TestMethod]
        public void Update_Snapshot_Success()
        {
            var expectedValue = new LongRunningTaskInstanceSnapshot
            {
                Id = Guid.NewGuid().ToString(),
                ParamJson = "{ data: 4 }",
                Result = new LongRunningTaskFileInMemResult
                {
                    Contents = new byte[] { 1, 2, 3 },
                    EnforceInMemory = true,
                    MimeType = "application/octet-stream",
                    FileName = "f4"
                },
                ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                Status = new LongRunningTaskInstanceStatus
                {
                    TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                    TaskStatus = new LongRunningTaskStatus
                    {
                        Details = "details4",
                        Progress = 99f
                    }
                },
                Title = "Title 4",
                Type = LongRunningTaskTypeEnum.GccsReportPdf,
                Username = "user4",
                SnapshotDateCreated = DateTime.UtcNow,
                Order = DateTime.UtcNow.Ticks
            };

            _repo.Insert(expectedValue);

            var value = _repo.Get(expectedValue.Id);

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(new LongRunningTaskInstanceSnapshot().Equals(expectedValue, value), "Returned value is different than the expected value.");

            expectedValue.ParamJson = "{ data: 5 }";
            expectedValue.Result = new LongRunningTaskObjectResult { Data = 123 };
            expectedValue.Status.TaskStatus.Progress = 100f;
            expectedValue.Status.TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Finished;

            _repo.Update(expectedValue);

            value = _repo.Get(expectedValue.Id);

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(new LongRunningTaskInstanceSnapshot().Equals(expectedValue, value), "Returned value is different than the expected value.");
        }

        [TestMethod]
        public void Delete_Snapshot_Success()
        {
            var expectedValue = new LongRunningTaskInstanceSnapshot
            {
                Id = Guid.NewGuid().ToString(),
                ParamJson = "{ data: 4 }",
                Result = new LongRunningTaskFileInMemResult
                {
                    Contents = new byte[] { 1, 2, 3 },
                    EnforceInMemory = true,
                    MimeType = "application/octet-stream",
                    FileName = "f4"
                },
                ResultType = LongRunningTaskResultTypeEnum.FileInMem,
                Status = new LongRunningTaskInstanceStatus
                {
                    TaskInstanceStatus = LongRunningTaskInstanceStatusEnum.Running,
                    TaskStatus = new LongRunningTaskStatus
                    {
                        Details = "details4",
                        Progress = 99f
                    }
                },
                Title = "Title 4",
                Type = LongRunningTaskTypeEnum.GccsReportPdf,
                Username = "user4",
                SnapshotDateCreated = DateTime.UtcNow,
                Order = DateTime.UtcNow.Ticks
            };

            _repo.Insert(expectedValue);

            var value = _repo.Get(expectedValue.Id);

            Assert.IsNotNull(value, "Returned value is null.");
            Assert.IsTrue(new LongRunningTaskInstanceSnapshot().Equals(expectedValue, value), "Returned value is different than the expected value.");

            _repo.Delete(expectedValue.Id);

            value = _repo.Get(expectedValue.Id);

            Assert.IsNull(value, "Value was not deleted.");
        }
    }
}
